//////////////////////////////////////////////////
// EASIM project
// easim.mobi.RandomWaypoint
// 2007/6/6 3:15 PM
// Cong Liu
// gzcong@gmail.com

// Copyright (C) 2007
// All rights reserved.
// Refer to LICENSE of JIST (Java In Simulation Time) for terms and conditions of use.

package easim.mobi;

import jist.runtime.JistAPI;
import jist.swans.Constants;
import easim.net.Node;

public class RandomWaypoint extends Mobility implements JistAPI.DoNotRewrite
{

  ///////////////////////////////////
  // Random Waypoint Configuration
  //

  public static float STEP_SIZE = 1;
  public static float MIN_SPEED = 50;
  public static float MAX_SPEED = 100;
  public static long MIN_PAUSE_TIME = 10 * Constants.SECOND;
  public static long MAX_PAUSE_TIME = 50 * Constants.SECOND;
  public static int WIDTH = 800;
  public static int HEIGHT = 600;

  ///////////////////////////////////
  // Random Waypoint Data
  //

  protected float x, y;
  protected int steps;
  protected long delay;

  public RandomWaypoint(Node node) {
    super(node);
  }

  public void start() {
    steps = -1;
    super.start();
  }

  public void nextWaypoint() {
    x = (float)Constants.random.nextFloat() * WIDTH;
    y = (float)Constants.random.nextFloat() * HEIGHT;
    float dx = node.getX() - x;
    float dy = node.getY() - y;
    float distance = (float)Math.sqrt(dx * dx + dy * dy);
    steps = (int)(distance / STEP_SIZE);
    if (steps == 0) steps = 1;
    float speed = MIN_SPEED + (MAX_SPEED - MIN_SPEED) * Constants.random.nextFloat();
    delay = (long)(Constants.SECOND * distance / speed);
  }

	public Movement next() {
    if (steps == 0 || steps == -1) {
      long pauseTime = MIN_PAUSE_TIME + (long)((MAX_PAUSE_TIME - MIN_PAUSE_TIME) * Constants.random.nextDouble());
      if (steps == -1) {
        pauseTime = (long)(pauseTime * Constants.random.nextDouble());
      }
      Movement movement = new Movement();
      movement.x = node.getX();
      movement.y = node.getY();
      movement.delay = pauseTime;
      nextWaypoint();
      return movement;
    }
    else {
      float x0 = node.getX();
      float y0 = node.getY();
      float dx = x - x0;
      float dy = y - y0;
      Movement movement = new Movement();
      movement.x = x0 + dx / steps;
      movement.y = y0 + dy / steps;
      movement.delay = delay / steps;
      delay -= movement.delay;
      -- steps;
      return movement;
    }
	}

}
